package com.violet.uaa.server.security.filter;

import com.violet.auth.client.util.JwtTokenUtil;
import com.violet.uaa.server.login.entity.CustomAuthenticationDetailsSource;
import com.violet.uaa.server.login.service.VioletUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;

/**
 * 类说明: 身份令牌过滤器
 *
 * @author wqf
 * @date 2022/6/20 14:34
 */
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private VioletUserDetailsService violetUserDetailsService;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    /**
     * / JWT 令牌请求头（即：Authorization）
     */
    @Value("${jwt.authentication}")
    private String authHead;
    /**
     * jwr 前缀
     */
    @Value("${jwt.separator}")
    private String separator;

    /**
     * 方法描述: 从请求中获取 JWT 令牌，并根据令牌获取用户信息，最后将用户信息封装到 Authentication 中，方便后续校验
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    @NotNull HttpServletResponse response,
                                    @NotNull FilterChain filterChain) throws ServletException, IOException {
        // 从请求中获取 JWT 令牌的请求头（即：Authorization）
        String authToken = request.getHeader(authHead);
        // 如果请求头不为空，并且以 JWT 令牌前缀（即：Bearer ）开头
        if (authToken != null && authToken.startsWith(this.separator)) {
            //从 JWT 令牌中获取用户名
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            //记录日志
            log.info("checking username:{}", username);
            // 如果用户名不为空，并且 SecurityContextHolder 中的 Authentication 为空（表示该用户未登录）
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                //从数据库中加载用户信息
                UserDetails userDetails = violetUserDetailsService.loadUserByUsername(username);
                if (userDetails != null) {
                    Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
                    // 将用户信息封装到 UsernamePasswordAuthenticationToken 对象中（即：Authentication）
                    // 参数：用户信息、密码（因为 JWT 令牌中没有密码，所以这里传 null）、用户权限
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
                    // 将请求中的详细信息（即：IP、SessionId 等）封装到 UsernamePasswordAuthenticationToken 对象中方便后续校验
                    authentication.setDetails(new CustomAuthenticationDetailsSource().buildDetails(request));
                    // 记录日志
                    log.info("authenticated user:{}", authentication);
                    // 将 UsernamePasswordAuthenticationToken 对象封装到 SecurityContextHolder 中方便后续校验
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        // 放行，执行下一个过滤器
        filterChain.doFilter(request, response);
    }
}